package com.light.view;

import atlantafx.base.controls.CustomTextField;
import atlantafx.base.theme.Styles;
import atlantafx.base.theme.Tweaks;
import com.light.component.LevelTableCell;
import com.light.component.OperationTableCell;
import com.light.component.TooltipTableRow;
import com.light.model.GitAuthInfo;
import com.light.model.GitProject;
import com.light.thread.FxAsyncTask;
import com.light.thread.FxTask;
import com.light.thread.FxThreadPoolTask;
import com.light.util.DateUtils;
import com.light.util.FxApplicationContextUtils;
import com.light.util.H2PoolUtils;
import com.light.util.JGitUtils;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.collections.FXCollections;
import javafx.geometry.Insets;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.CheckBoxTableCell;
import javafx.scene.control.cell.ProgressBarTableCell;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.stage.DirectoryChooser;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.jgit.transport.CredentialsProvider;
import org.kordamp.ikonli.bootstrapicons.BootstrapIcons;
import org.kordamp.ikonli.javafx.FontIcon;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

public class ManagerView extends StackPane {
    public static final Logger LOGGER = LoggerFactory.getLogger(ManagerView.class);
    // 上半部分：搜索、更新
    private CustomTextField searchField;
    private final Button updateButton = new Button("更新");
    private final Button addLocalButton = new Button("添加本地项目");
    private final Button deleteBatchButton = new Button("批量删除");
    private final DirectoryChooser dirChooser = new DirectoryChooser();
    private final HBox hBox = new HBox(5);

    // 表格
    private final CheckBox selectAll = new CheckBox();
    private TableView<GitProject> tableView;

    // 整体
    private final VBox vBox = new VBox(10);

    public ManagerView() {
        this.getChildren().add(vBox);
        initialize();
        initEvent();
    }

    public void initialize() {
        searchField = new CustomTextField();
        searchField.setLeft(new FontIcon(BootstrapIcons.SEARCH));
        searchField.setPromptText("请输入仓库名称或者作者名称进行搜索...");
        addLocalButton.setMnemonicParsing(true);
        updateButton.setMnemonicParsing(true);
        deleteBatchButton.setMnemonicParsing(true);
        hBox.getChildren().addAll(searchField, addLocalButton, updateButton, deleteBatchButton);
        HBox.setHgrow(searchField, Priority.ALWAYS);

        // 初始化表格
        initTable();

        vBox.getChildren().addAll(hBox, tableView);
        vBox.setPadding(new Insets(5, 2, 5, 2));
        VBox.setVgrow(tableView, Priority.ALWAYS);
    }

    public void initTable() {
        var select = new TableColumn<GitProject, Boolean>();
        select.setGraphic(selectAll);
        select.setSortable(false);
        select.setCellFactory(CheckBoxTableCell.forTableColumn(select));
        select.setCellValueFactory(param -> param.getValue().selected());
        select.setPrefWidth(40d);
        select.setMaxWidth(40d);
        select.setMinWidth(40d);

        var id = new TableColumn<GitProject, Integer>("序号");
        id.setCellValueFactory(c -> c.getValue().id().asObject());
        id.setPrefWidth(50d);
        id.setMaxWidth(50d);
        id.setMinWidth(50d);

        var warehouse = new TableColumn<GitProject, String>("仓库");
        warehouse.setCellValueFactory(c -> c.getValue().name());

        var author = new TableColumn<GitProject, String>("作者");
        author.setCellValueFactory(c -> c.getValue().author());

        var branch = new TableColumn<GitProject, String>("分支");
        branch.setSortable(false);
        branch.setCellValueFactory(c -> c.getValue().branch());

        var level = new TableColumn<GitProject, Integer>("学习等级");
        level.setCellFactory(LevelTableCell.forTableColumn());
        level.setCellValueFactory(c -> c.getValue().level().asObject());

        var process = new TableColumn<GitProject, Double>("更新进度");
        process.setSortable(false);
        process.setCellFactory(ProgressBarTableCell.forTableColumn());
        process.setCellValueFactory(c -> c.getValue().downloadRate().asObject());

        var operation = new TableColumn<GitProject, Integer>("操作");
        operation.setSortable(false);
        operation.setCellFactory(OperationTableCell.forTableColumn());
        operation.setCellValueFactory(c -> c.getValue().id().asObject());
        operation.setPrefWidth(120d);
        operation.setMaxWidth(120d);
        operation.setMinWidth(120d);

        tableView = new TableView<>(FxApplicationContextUtils.GIT_PROJECT_OBSERVABLE_LIST);
        tableView.getColumns().setAll(select, id, warehouse, author, branch, level, process, operation);
        tableView.setRowFactory(TooltipTableRow.forTableRow());
        tableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
        tableView.getStyleClass().addAll(Tweaks.EDGE_TO_EDGE, Styles.BORDERED);
        tableView.getSelectionModel().selectFirst();
        tableView.setMaxWidth(Double.MAX_VALUE);
        tableView.setMinHeight(300);
        tableView.setEditable(true);
    }

    public void initEvent() {
        // 全选按钮事件
        selectAll.setOnAction(event -> {
            tableView.getItems().forEach(
                    item -> item.selected().set(selectAll.isSelected())
            );
            event.consume();
        });

        /*
         * 添加本地项目按钮事件
         * 输入框 让用户键入代码存放路径
         * 按钮   加载
         */
        addLocalButton.setOnAction(btn -> {
            dirChooser.setInitialDirectory(new File(H2PoolUtils.queryDictByLabel("GIT_CURRENT_LOCAL_DIR", "") + File.separator));
            File file = dirChooser.showDialog(getScene().getWindow());
            if (null != file) {
                H2PoolUtils.updateDictData("GIT_CURRENT_LOCAL_DIR", file.getPath());
                FxAsyncTask.runOnce("加载本地项目", () -> {
                    JGitUtils.parseLocalProjectPath(file);
                    JGitUtils.parseLocalProject();
                });
            }
        });

        // 搜索框执行逻辑
        searchField.setOnKeyReleased(event -> {
            String text = searchField.getText();
            if (StringUtils.isNotBlank(text)) {
                List<GitProject> list;
                if (FxApplicationContextUtils.GIT_PROJECT_OBSERVABLE_LIST.size() > 10000) {
                    list = FxApplicationContextUtils.GIT_PROJECT_OBSERVABLE_LIST.
                            parallelStream().filter(param -> param.name().get().toUpperCase().contains(text.toUpperCase()) || param.author().get().toUpperCase().contains(text.toUpperCase())).toList();
                } else {
                    list = FxApplicationContextUtils.GIT_PROJECT_OBSERVABLE_LIST.
                            stream().filter(param -> param.name().get().toUpperCase().contains(text.toUpperCase()) || param.author().get().toUpperCase().contains(text.toUpperCase())).toList();
                }
                tableView.setItems(FXCollections.observableList(list));
            } else {
                tableView.setItems(FxApplicationContextUtils.GIT_PROJECT_OBSERVABLE_LIST);
            }
        });

        // 全部更新按钮
        updateButton.setOnMouseClicked(event -> {
            event.consume();
            JGitUtils.GITHUB_FAIL_NUMBER.set(0);
            JGitUtils.GITEE_FAIL_NUMBER.set(0);
            List<GitProject> list = tableView.getItems().stream().filter(param -> param.selected().get()).toList();
            if (!list.isEmpty()) {
                updateButton.setDisable(true);
            }
            // 更新更新数量
            FxApplicationContextUtils.UPDATE_PROPERTY.set(String.valueOf(FxApplicationContextUtils.UPDATE_NUMBER.addAndGet(list.size())));
            Iterator<GitProject> iterator = list.iterator();
            FxAsyncTask.runOnce(System.currentTimeMillis(), "批量更新", () -> {
                        while (iterator.hasNext()) {
                            if (FxThreadPoolTask.THREAD_DEALING_NUM.get() >= 5) {
                                Thread.sleep(1500);
                                continue;
                            }
                            GitProject project = iterator.next();
                            FxThreadPoolTask.runVirtualPool(FxTask.createTask(System.currentTimeMillis(), "更新项目",
                                    () -> {
                                        SimpleDoubleProperty rate = project.downloadRate();
                                        File localRepoFile = new File(project.local().get());
                                        String remoteUrl = project.remote();
                                        String type = JGitUtils.getType(remoteUrl);
                                        if ("Gitee".equals(type) && JGitUtils.GITEE_FAIL_NUMBER.get() < 10) {
                                            pull(project, localRepoFile, remoteUrl, rate);
                                        } else if ("Github".equals(type) && JGitUtils.GITHUB_FAIL_NUMBER.get() < 5) {
                                            pull(project, localRepoFile, remoteUrl, rate);
                                        } else if ("other".equals(type)) {
                                            pull(project, localRepoFile, remoteUrl, rate);
                                        }
                                    },
                                    () -> {
                                        // 正在运行task -1
                                        FxThreadPoolTask.THREAD_DEALING_NUM.decrementAndGet();
                                        FxApplicationContextUtils.UPDATE_PROPERTY.set(String.valueOf(FxApplicationContextUtils.UPDATE_NUMBER.decrementAndGet()));
                                        selectAll.setSelected(false);
                                    }, () -> {
                                        // 正在运行task -1
                                        FxThreadPoolTask.THREAD_DEALING_NUM.decrementAndGet();
                                        FxApplicationContextUtils.UPDATE_PROPERTY.set(String.valueOf(FxApplicationContextUtils.UPDATE_NUMBER.decrementAndGet()));
                                    }));
                        }
                    },
                    () -> updateButton.setDisable(false),
                    () -> updateButton.setDisable(false));
        });

        // 删除
        deleteBatchButton.setOnMouseClicked(event -> {
            List<GitProject> list = tableView.getItems().stream().filter(param -> param.selected().get()).toList();
            list.forEach(project -> {
                int num = H2PoolUtils.deleteGitProject(project);
                if (num > 0) {
                    FxApplicationContextUtils.GIT_PROJECT_OBSERVABLE_LIST.remove(project);
                }
            });
            tableView.setItems(FxApplicationContextUtils.GIT_PROJECT_OBSERVABLE_LIST);
            searchField.setText("");
            selectAll.setSelected(!selectAll.isSelected());
        });
    }

    public static void pull(GitProject project, File localRepoFile, String remoteUrl, SimpleDoubleProperty rate) {
        GitAuthInfo existsAuthInfo = JGitUtils.isExistsAuthInfo(project.remote());
        CredentialsProvider provider = null;
        if (existsAuthInfo != null) {
            provider = JGitUtils.createCredential(existsAuthInfo.username(), existsAuthInfo.password());
        }
        boolean pull = JGitUtils.pull(remoteUrl, localRepoFile, provider, rate);
        if (pull) {
            project.updateTime().set(DateUtils.formatDateTime(new Date()));
            H2PoolUtils.updateGitProject(project);
            project.selected().set(false);
        }
    }
}
